using System;
using System.Collections;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;

namespace SinceTimes.NetWork
{
    public class ConnectionWebSocket : Connection
    {
        public ConnectionWebSocket(MonoBehaviour owner) : base(owner)
        { 
        
        }
        ClientWebSocket WS;


        public override bool Connected => WS!=null && WS.State== WebSocketState.Open &&  ConnectOK;


        public override string State => WS != null ? WS.State.ToString() : "NULL";

        //protected override IDataPackage _DoInitDataPacker()
        //{
        //    return new DataPackager();
        //}
        protected override void _DoConnect() => _ConnectAsync();//Owner.StartCoroutine(_Conntect_Runer()); 

     



        async Task _ConnectAsync()
        {

            WS = new ClientWebSocket();
            WS.Options.UseDefaultCredentials = true;

            
            string url = Url;

            if (Port > 0)
                url = $"{url}:{Port}";

            Uri uri = new Uri(url);

            CancellationToken canceler = new CancellationToken();


            if (Net.SHOWLOG) 
                Debug.Log($"[Net.ConnectionWebSocket.ConnectAsync({uri})].................");

            

            await WS.ConnectAsync(uri, canceler);

           
            //await Task.Delay(300);

            if (WS.State != WebSocketState.Open)
            {
                // 无法打开 WebSocketState...错误退出.
                if (Net.SHOWERROR) 
                    Debug.LogError($"[Net.ConnectionWebSocket.State({WS.State})].................");

                Error = WS.CloseStatus?.ToString();    

                _DoClose(true);
                return;
            }


            if (Net.SHOWLOG) 
                Debug.Log($"[Net.ConnectionWebSocket.ConnectAsync({uri})].OK.....................");

            //如果有登录验证...
            if (_Buff_Authenticate != null && _Buff_Authenticate.Length > 0)
            {
                //发送登录验证
                await WS.SendAsync(new ArraySegment<byte>(_Buff_Authenticate), WebSocketMessageType.Binary, true, canceler);
                if (Net.SHOWLOG) 
                    Debug.Log($"[Net.ConnectionWebSocket.SendAsync(_Buff_Authenticate)]SendAsync:_Buff_Author:{Net.BYTES_STRING(_Buff_Authenticate)}");

                int N = 0;// 有可能存在 其他包再身份验证回包前发送..
                while (N++ < 20)
                {

                    //等待登录返回
                    var result = await WS.ReceiveAsync(new ArraySegment<byte>(_BUFF), CancellationToken.None);
                    if (Net.SHOWLOG)
                        Debug.Log($"[Net.ConnectionWebSocket.ReceiveAsync(_Buff_Author)]ReceiveAsync:count{result.Count} ; data:{Net.BYTES_STRING(_BUFF, 0, result.Count)}");

                
                    //如果包 合法
                    if (result.Count > 0)
                    {
                        ushort len = Net.BYTE_USHORT(_BUFF, 0); //消息报长度
                        ushort type = Net.BYTE_USHORT(_BUFF, 2);//消息类型

                        if (type == 20002)
                        {
                            //正确的登录--有身份验证
                            if (Net.SHOWLOG)
                                Debug.Log($"[Net.ConnectionWebSocket]身份验证正确.....OK:{N}");

                            Error = "";

                            if (OnUserAuth != null)
                            {
                                try
                                {
                                    string err = OnUserAuth.Invoke(this, _BUFF, 0,len);
                                    if (!string.IsNullOrEmpty(err))
                                    {
                                        Debug.Log($"[Net.ConnectionWebSocket.OnUserAuth]身份验证失败:{err}.....");
                                        _DoClose();
                                        return;
                                    }
                                }
                                catch
                                {

                                }

                            
                            }
                            _DoConnectSuccess();

                            return;
                        }
                        //else
                        //{
                        //    Error = $"Authenticated Error:type={type}";
                        //}
                    }
                    //else
                    //{
                    //    Error = $"Authenticated Error:result.Count=0";
                    //}
                }
                if (Net.SHOWLOG)
                    Debug.Log($"[Net.ConnectionWebSocket]身份验证多次失败");
                Error = $"Authenticated Error";

            }
            else
            {
                //正确的登录--无身份验证
                Error = "";
                _DoConnectSuccess();
                return;
            }

            // 没有能够正确链接..退出..
            _DoClose();


        }
        void _DoConnectSuccess()
        {

            // 建立链接..开始循环接受数据
            OnConnectSuccess();
            _DoReceive();
        }

        


        byte[] _BUFF=new byte[BUFF_MAX];
        async Task _DoReceive()
        {
            try
            {
                if(_BUFF==null)
                    _BUFF=new byte[BUFF_MAX];
                do
                {
                    RuntimeState.Receiving = true;
                    var result = await WS.ReceiveAsync(new ArraySegment<byte>(_BUFF), CancellationToken.None);
                    


                    //如果包 合法
                    if (result.Count > 0)
                    {
                        _OnReceive (_BUFF,0,(uint)result.Count);
                    }
                    else
                    {
                        Error = "Receive zero";
                        break;
                    
                    }
                }
                while (!WS.CloseStatus.HasValue);


                
                Error = "CloseStatus" + WS.CloseStatus?.ToString();

            }
            catch (Exception exception)
            {
                Error = exception.Message;
            }
            finally
            {
                RuntimeState.Receiving = false;
                _DoClose(true);
        
            }
        }

        protected override void _DoClose(bool callback = false)
        {
            try
            {
                if (WS != null && WS.State == WebSocketState.Open)
                {
                    WS.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);
                }
            }catch
            {

            }


            base._DoClose(callback);
        }



        protected override  int _DoSend(byte[] data)
        {
            if (data == null) return 0;



            CancellationToken canceler=new CancellationToken();

            try
            {
                WS.SendAsync(data, WebSocketMessageType.Binary, true, canceler);
                
                _OnSend(data);

                return data.Length;
            }catch(Exception e)
            {
                //if (Net.SHOWERROR) 
                    Debug.Log($"[Net.ConnectionWebSocket.Send] Error :{ (e!=null?e.Message:Error)}");

                _DoClose(true);
                return -1;
            }

            

        }
        protected override void RuntimeCheck()
        {
            base.RuntimeCheck();

            RuntimeState.State =( WS != null ? WS.State.ToString() : "null");
        }












    }
}

